package com.globo.opensocial;

import java.util.Stack;
import java.util.StringTokenizer;

import com.globo.opensocial.tags.ForTag;

public class Parser {

	private Stack<String> variables;
	private Application app;

	public Parser(Application app) {
		this.app = app;

		variables = new Stack<String>();

	}

	/**
	 * Before for.
	 * 
	 * @param var
	 * @param key
	 */
	public void push(String var, String key) {
		variables.add(var);
		variables.add(key);
	}

	/**
	 * Before for.
	 * 
	 * @param var
	 * @param key
	 */
	public void push(ForTag forTag) {
		variables.add(forTag.getKey());
		variables.add(forTag.getVar());
	}

	/**
	 * After For.
	 */
	public void pop() {
		variables.pop();
		variables.pop();
	}

	public String getArrayToken(String name) {
		return processToken(name, "A");
	}

	public String getValueToken(String name) {
		return processToken(name, "V");
	}

	/**
	 * Process a token.
	 * 
	 * @param token
	 * @param function
	 * @return
	 */
	private String processToken(String token, String function) {

		token = token.trim();

		String object = token;
		String value = null;

		if (token.indexOf(".") != -1) {
			object = token.split("\\.")[0];
			value = token.split("\\.")[1];
		}

		if (variables.indexOf(object) != -1) {
			return token;
		} else {
			if (value != null) {
				return "this." + function + "(\"" + object + "\")."
						+ safeFunctionParams(value);
			} else {
				return "this." + function + "(\"" + object + "\")";
			}
		}
	}

	/**
	 * Search a token in function params
	 * 
	 * @param input
	 * @return
	 */
	public String safeFunctionParams(String input) {

		StringBuffer output = new StringBuffer();

		String t = "()., ";

		StringTokenizer st = new StringTokenizer(input, t, true);

		boolean inParam = false;

		while (st.hasMoreTokens()) {
			String token = st.nextToken();
			if (inParam) {
				if (token.equals(")")) {
					inParam = false;
				}
				if (t.indexOf(token) != -1) {
					output.append(token);
				} else {
					output.append(getValueToken(token));
				}
			} else {
				if (token.equals("(")) {
					inParam = true;
				}
				output.append(token);
			}
		}
		return output.toString();
	}

	/**
	 * Handles logic to translate variables.
	 * 
	 * @param input
	 * @return
	 */
	public String filterText(String input) {

		StringBuffer output = new StringBuffer();

		StringTokenizer st = new StringTokenizer(input, "{}", true);

		boolean inToken = false;

		while (st.hasMoreTokens()) {
			String token = st.nextToken();

			if (inToken) {
				if (token.equals("}")) {
					inToken = false;
				} else {
					output.append("\" + " + getValueToken(token) + " + \"");
				}
			} else {
				if (token.equals("{")) {
					inToken = true;
				} else {
					output.append(token.replaceAll("\n", "\\n").replaceAll(
							"\\\"", "\\\\\""));
				}
			}
		}
		return output.toString();
	}

	/**
	 * Try gets the structure.
	 * 
	 * @param nodeValue
	 * @return
	 */
	public String safeIf(String nodeValue) {

		if (nodeValue.equals("true") || nodeValue.equals("1")) {
			return nodeValue;
		}
		/*
		 * if ( variables.indexOf(nodeValue) != 1 ) { return nodeValue; }
		 */

		if (nodeValue.matches("[a-zA-Z_0-9]+")) {
			return getValueToken(nodeValue);
		}

		StringBuffer output = new StringBuffer();

		StringTokenizer st = new StringTokenizer(nodeValue, "{}", true);

		boolean inToken = false;

		while (st.hasMoreTokens()) {
			String token = st.nextToken();

			if (inToken) {
				if (token.equals("}")) {
					inToken = false;
				} else {
					output.append(" " + getValueToken(token) + " ");
				}
			} else {
				if (token.equals("{")) {
					inToken = true;
				} else {
					output.append(token);
					// token.replaceAll("\n", "\\n").replaceAll( "\\\"",
					// "\\\\\""));
				}
			}
		}
		return output.toString();
	}

	/**
	 * Safe javascript function caller.
	 * 
	 * @TODO: Add safety code.
	 * @param input
	 * @return
	 */
	public String getSafeFunction(String input) {

		input = input.trim();

		if (input.startsWith("app.")) {

			StringBuffer out = new StringBuffer();
			out.append("function() {");
			out.append(safeIf(safeFunctionParams(input.replace("app.", app
					.getId()
					+ "."))));
			// processar aqui.
			out.append(";};");
			return out.toString();

		} else {
			StringBuffer out = new StringBuffer();
			out.append("function() {");
			out.append(input);
			out.append(";};");
			return out.toString();
		}
	}

}
